//
// Created by jiazhen on 2025/4/7.
//

#ifndef PLUGIN_EXAMPLE_PLUGINLOADER_H
#define PLUGIN_EXAMPLE_PLUGINLOADER_H

#include <dlfcn.h>
#include <string>

namespace jazz
{

    class PluginLoader
    {
    public:
        explicit PluginLoader(const std::string &plugin_path)
        {
            m_handle = dlopen(plugin_path.c_str(), RTLD_LAZY);
            if (!m_handle)
            {
                printf("Failed to open %s\n", plugin_path.c_str());
            }
            dlerror(); // 清除旧错误
        }

        ~PluginLoader()
        {
            if (m_handle)
            {
                dlclose(m_handle);
            }
        }

        bool success() const
        {
            return m_handle != nullptr;
        }

        template <typename ReturnType, typename... InputTypes>
        using FuncPtr = ReturnType (*)(InputTypes...);

        template <typename ReturnType, typename... InputTypes>
        FuncPtr<ReturnType, InputTypes...> getFunc(const char *func_name)
        {
            using Func = ReturnType (*)(InputTypes...);
            Func func = (Func)dlsym(m_handle, func_name);
            const char *dlsym_error = dlerror();
            if (dlsym_error)
            {
                printf("Cannot load symbol '%s'\n", dlsym_error);
                return nullptr;
            }
            return func;
        }

    private:
        void *m_handle = nullptr;
    };
} // jazz

#endif // PLUGIN_EXAMPLE_PLUGINLOADER_H
